/**
 * POrcamento.java
 * Copyright (C) 2009 Jose Mauro da Silva Sandy
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

package persistencia.notas;

import java.io.IOException;
import java.sql.*;
import plagio.postgres.ConnectionPostgres;
import negocio.notas.Orcamento;
import java.util.*;
import utils.*;

/**
 *
 * @author jmsandy
 */
public class POrcamento {

    //<editor-fold defaultstate="collapsed" desc="Attributes">
    private boolean error = false;
    //</editor-fold>

    //<editor-fold defaultstate="collapsed" desc="Acessores">
    public boolean isError(){
        return this.error;
    }
    //</editor-fold>

    //<editor-fold defaultstate="collapsed" desc="Table Columns">
    static final protected String K_TBL_Orcamento         = "Orcamento";
    static final protected String K_COL_cod_objeto        = "cod_objeto";
    static final protected String K_COL_numOrcamento      = "numorcamento";
    static final protected String K_COL_numOrcFornecedor  = "numorcfornecedor";
    static final protected String K_COL_dtValidade        = "dtvalidade";
    static final protected String K_COL_dtOrcamento       = "dtorcamento";
    static final protected String K_COL_valor             = "valor";
    static final protected String K_COL_situacao          = "situacao";
    static final protected String K_COL_fornecedor        = "fornecedor";
    static final public int K_REC_COD_OBJETO            = 1;
    static final public int K_REC_COD_ORC               = 2;
    //</editor-fold>

    //<editor-fold defaultstate="collapsed" desc="Constructor">
    /**
     * Construtor padrao. Responsavel por realizar a persistencia de um Orcamento
     * @throws java.io.IOException
     */
    public POrcamento() throws IOException{
        error = false;
    }
    //</editor-fold>

    //<editor-fold defaultstate="collapsed" desc="Methods">
    // Realiza a construcao basica de um select
    private StringBuilder formSelector(){
        StringBuilder query = new StringBuilder();
        query.append("SELECT " + K_COL_cod_objeto + ", " + K_COL_numOrcamento);
        query.append(", " + K_COL_numOrcFornecedor + ", " + K_COL_dtValidade);
        query.append(", " + K_COL_dtOrcamento + ", " + K_COL_valor + ", ");
        query.append(K_COL_situacao + ", " + K_COL_fornecedor + " FROM \"");
        query.append(K_TBL_Orcamento + "\"");
        return query;
    }

    /**
     * Responsavel por criar a estrutura para inserir o objeto
     * @return construtor do objeto a ser inserido
     */
    private String formInsert(){
        return "INSERT INTO \"" + K_TBL_Orcamento + "\"(" + K_COL_cod_objeto +
           ", " + K_COL_numOrcFornecedor + ", " + K_COL_dtValidade + ", " +
           K_COL_dtOrcamento + ", " + K_COL_valor + ", " + K_COL_situacao + ", "
           + K_COL_fornecedor + ") VALUES (?, ?, ?, ?, ?, ?, ?)";
    }

    /**
     * Responsavel por criar a estrutura para atualizar o objeto
     * @param obj - Objeto a ser atualizado na base de dados
     * @return construtor do objeto a ser atualizado
     */
    private String formUpdate(Orcamento obj){
        StringBuilder query = new StringBuilder();
        query.append("UPDATE \"" + K_TBL_Orcamento + "\" SET ");
        query.append(K_COL_numOrcFornecedor + " = '" +
                                            obj.getNumOrcFornecedor() + "', ");
        query.append(K_COL_valor + " = '" + obj.getValor() + "', ");
        query.append(K_COL_situacao + " = '" + obj.getSituacao() + "', ");
        query.append(K_COL_fornecedor + " = '" + obj.getFornecedor() + "'");
        query.append(obj.getDtValidade() != null ? (" , " +
                    K_COL_dtValidade + " = '"  + obj.getDtValidade() + "'"):"");
        query.append(obj.getDtOrcamento() != null ? (" , " +
                  K_COL_dtOrcamento + " = '"  + obj.getDtOrcamento() + "'"):"");
        query.append(" WHERE " + K_COL_cod_objeto + " = '" +
                                        obj.getCod_objeto() + "'");
        return query.toString();
    }

    /**
     * Responsavel por criar a estrutura para deletar o objeto
     * @param obj - Objeto a ser deletado na base de dados
     * @return construtor do objeto a ser deletado
     */
    private String formDelete(Orcamento obj){
        return "DELETE FROM \"" + K_TBL_Orcamento + "\" WHERE " +
                K_COL_cod_objeto + " = '" + obj.getCod_objeto() + "'";
    }

    /**
     * Responsavel por inserir um objeto na base de dados
     * @param obj - objeto a ser inserido na base de dados
     * @return TRUE - caso afirmativo e FALSE - caso contrario
     */
    public Boolean insert(Orcamento obj){
        Boolean status = true;

        try{
            ConnectionPostgres conn = new ConnectionPostgres(); // nova conexao
            // Realiza a conexao com o servidor
            conn = ConnectionSystem.connectionSystem();

            // Monta o objeto em uma instrucao SQL para insercao no banco
            PreparedStatement stat;
            String query = formInsert();
            stat = conn.getConnection().prepareStatement(query);
            stat.setString(1, obj.getCod_objeto());
            stat.setInt(2, obj.getNumOrcFornecedor());
            stat.setDate(3, (obj.getDtValidade() != null ?
                new java.sql.Date(obj.getDtValidade().getTime()) : null));
            stat.setDate(4, (obj.getDtOrcamento() != null ?
                     new java.sql.Date(obj.getDtOrcamento().getTime()) : null));
            stat.setDouble(5, obj.getValor());
            stat.setInt(6, utils.StatusOrcamento.PENDENTE);
            stat.setString(7, obj.getFornecedor());
            stat.executeUpdate();
            stat.close();
            conn.closeConnection();
        }
        catch(Exception ex){
            Log.gravarLog(RedirectStackTrace.stackTraceToString(ex), this);
            error = true;
            status = false;
        }
        return status;
    }

    /**
     * Responsavel por atualizar um objeto na base de dados
     * @param obj - objeto a ser atualizado na base de dados
     * @return TRUE - caso afirmativo e FALSE - caso contrario
     */
    public Boolean update(Orcamento obj){
        Boolean status = true;

        try{
            ConnectionPostgres conn = new ConnectionPostgres(); // nova conexao

            // Realiza a conexao com o servidor
            conn = ConnectionSystem.connectionSystem();

            // Monta o objeto em uma instrucao SQL para atualizacao no banco
            PreparedStatement stat;
            String query = formUpdate(obj);
            stat = conn.getConnection().prepareStatement(query);
            stat.executeUpdate();
            stat.close();
            conn.closeConnection();
        }
        catch(Exception ex){
            Log.gravarLog(RedirectStackTrace.stackTraceToString(ex), this);
            error = true;
            status = false;
        }
        return status;
    }

    /**
     * Responsavel por deletar um objeto na base de dados
     * @param obj - objeto a ser deletado na base de dados
     * @return TRUE - caso afirmativo e FALSE - caso contrario
     */
    public Boolean delete(Orcamento obj){
        Boolean status = true;

        try{
            ConnectionPostgres conn = new ConnectionPostgres(); // nova conexao

            // Realiza a conexao com o servidor
            conn = ConnectionSystem.connectionSystem();

            // Monta o objeto em uma instrucao SQL para atualizacao no banco
            PreparedStatement stat;
            String query = formDelete(obj);
            stat = conn.getConnection().prepareStatement(query);
            stat.executeUpdate();
            stat.close();
            conn.closeConnection();
        }
        catch(Exception ex){
            Log.gravarLog(RedirectStackTrace.stackTraceToString(ex), this);
            error = true;
            status = false;
        }
        return status;
    }

    /**
     * Recupera um objeto orcamento pelo numero fornecido
     * @param codOrc codigo do orcamento a ser procurado
     * @return o orcamento encontrado ou NULL
     */
    public Orcamento refresh(String codOrc, int tipo){
        Orcamento orc = new Orcamento(); // objeto de retorno

        StringBuilder query = this.formSelector();
        query.append(" WHERE " + (tipo == K_REC_COD_ORC ?
                                 K_COL_numOrcamento + " = " + codOrc + "" :
                                 K_COL_cod_objeto + " = '" + codOrc + "'"));
        try{
            ConnectionPostgres conn = new ConnectionPostgres(); // nova conexao

            // Realiza a conexao com o servidor
            conn = ConnectionSystem.connectionSystem();

            Statement stat = conn.getConnection().createStatement();

            // Verifica a existencia do registro de retorno
            ArrayList<Orcamento> lstOrcamentos = new ArrayList<Orcamento>();
            lstOrcamentos = mapear(stat.executeQuery(query.toString()));
            if(lstOrcamentos.size() > 0) orc = lstOrcamentos.get(0);
            else orc = null;

        }catch(Exception ex){
            Log.gravarLog(RedirectStackTrace.stackTraceToString(ex), this);
            error = true;
            orc = null;
        }
        return orc;
    }

    /**
     * Recupera o ultimo codigo do orcamento inserido
     */
    public Integer recUltCodigo(){
        Integer valRet = 0;             // valor de retorno

        StringBuilder query = this.formSelector();
        // Clausula where
        query.append(" ORDER BY " + K_COL_numOrcamento + " DESC");

        try{
            ConnectionPostgres conn = new ConnectionPostgres(); // nova conexao

            // Realiza a conexao com o servidor
            conn = ConnectionSystem.connectionSystem();

            Statement stat = conn.getConnection().createStatement();

            // Verifica a existencia do registro de retorno
            ArrayList<Orcamento> lstOrcamentos = new ArrayList<Orcamento>();
            lstOrcamentos = mapear(stat.executeQuery(query.toString()));
            if(lstOrcamentos.size() > 0){
                Orcamento orc = new Orcamento();
                orc = lstOrcamentos.get(0);
                valRet = orc.getNumOrcamento();
            }
        }catch(Exception ex){
            Log.gravarLog(RedirectStackTrace.stackTraceToString(ex), this);
            error = true;
            valRet = 0;
        }
        return valRet;
    }

    /**
     * Responsavel por recuperar uma lista de todos os objetos que satisfacam
     * as condicoes recebidas para o objeto
     * @param orc: caracteristicas do orcamento a ser produrado
     * @return lista contendo todos os objetos recuperados
     */
    public ArrayList<Orcamento> recLstOrcamentos(Orcamento orc){
        // Lista de objetos de retorno
        ArrayList<Orcamento> lstOrcamentos = new ArrayList<Orcamento>();
        StringBuilder query = this.formSelector();
        StringBuilder crit  = new StringBuilder();
        // Clausula where
        
        // Verifica se foi informado um fornecedor para busca
        if(orc.getFornecedor() != null){
            crit.append(" AND " + K_COL_fornecedor + " = '" +
                                                     orc.getFornecedor() + "'");
        }
        // Verifica se foi informada uma situacao
        if(orc.getSituacao() != null){
            crit.append(" AND " + K_COL_situacao + " = '" +
                                                     orc.getSituacao() + "'");
        }
        // Verifica se foi informada uma data de orcamento
        if(orc.getDtOrcamento() != null){
            crit.append(" AND " + K_COL_dtOrcamento + " = '" +
                                                    orc.getDtOrcamento() + "'");
        }
        // Verifica se foi informada um numero
        if(orc.getNumOrcFornecedor() > 0 ){
            crit.append(" AND " + K_COL_numOrcFornecedor + " = '" +
                                               orc.getNumOrcFornecedor() + "'");
        }
        // Verifica se foi informada uma data de validade
        if(orc.getDtValidade() != null){
            crit.append(" AND " + K_COL_dtValidade + " = '" +
                                                    orc.getDtValidade() + "'");
        }
        try{
            ConnectionPostgres conn = new ConnectionPostgres(); // nova conexao

            // Realiza a conexao com o servidor
            conn = ConnectionSystem.connectionSystem();

            Statement stat = conn.getConnection().createStatement();

            if(crit.toString().startsWith(" AND ")){
                query.append(" WHERE " +
                crit.toString().substring(4, crit.toString().length()));
                lstOrcamentos =  mapear(stat.executeQuery(query.toString()));
            }
            else{
                lstOrcamentos = null;
            }
        }catch(Exception ex){
            Log.gravarLog(RedirectStackTrace.stackTraceToString(ex), this);
            error = true;
            lstOrcamentos = null;
        }
        return lstOrcamentos;
    }

    /**
     * Verifica se existe um orcamento para um dado fornecedor
     * @param idFornecedor identificador do fornecedor
     * @return TRUE se existe alguma nota e FALSE caso contrario
     */
    public Boolean existsForn(String idFornecedor){
        Boolean ret = false;
        try{
            StringBuilder query = new StringBuilder();
            query.append("SELECT " + K_COL_cod_objeto + " FROM \"");
            query.append(K_TBL_Orcamento + "\" WHERE " + K_COL_fornecedor);
            query.append(" = '" + idFornecedor + "'");

            ConnectionPostgres conn = new ConnectionPostgres(); // nova conexao

            // Realiza a conexao com o servidor
            conn = ConnectionSystem.connectionSystem();
            Statement stat = conn.getConnection().createStatement();
            ret = stat.executeQuery(query.toString()).next();
        }catch(Exception ex){
            Log.gravarLog(RedirectStackTrace.stackTraceToString(ex), this);
            error = true;
        }
        return ret;
    }

    /**
     * Verifica se o orcamento a ser excluido pertence a alguma nota
     * @param idOrc identificador do orcamento
     * @return TRUE se existe alguma nota encontrada e FALSE caso contrario
     */
    public Boolean existsNota(String idOrc){
        Boolean ret = false;
        try{
            StringBuilder query = new StringBuilder();
            query = formSelector();
            query.append(" WHERE " + K_COL_cod_objeto + " IN (SELECT ");
            query.append(PNotaCompra.K_COL_orcamento + " FROM \"");
            query.append(PNotaCompra.K_TBL_Nota + "\" WHERE ");
            query.append(PNotaCompra.K_COL_orcamento + " = '" + idOrc + "')");

            ConnectionPostgres conn = new ConnectionPostgres(); // nova conexao

            // Realiza a conexao com o servidor
            conn = ConnectionSystem.connectionSystem();
            Statement stat = conn.getConnection().createStatement();
            ret = stat.executeQuery(query.toString()).next();
        }catch(Exception ex){
            Log.gravarLog(RedirectStackTrace.stackTraceToString(ex), this);
            error = true;
        }
        return ret;
    }

    /**
     * Responsavel por converter o objeto vindo do banco de dados para um
     * modelo de objeto
     * @param result - result que obtem toda lista recebida do servidor
     * @return os objetos mapeados
     * @throws java.sql.SQLException
     */
    private ArrayList<Orcamento> mapear(ResultSet result) throws SQLException{
        ArrayList<Orcamento> lstOrcamentos = new ArrayList<Orcamento>();

        // Converte todo result recebido para uma lista de objetos
        while(result.next()){
            Orcamento orcamento = new Orcamento();
            orcamento.setCod_objeto(result.getString(1));
            orcamento.setNumOrcamento(result.getInt(2));
            orcamento.setNumOrcFornecedor(result.getInt(3));
            orcamento.setDtValidade(result.getDate(4));
            orcamento.setDtOrcamento(result.getDate(5));
            orcamento.setValor(result.getDouble(6));
            orcamento.setSituacao(result.getInt(7));
            orcamento.setFornecedor(result.getString(8));

            orcamento.setIsNew(false);

            lstOrcamentos.add(orcamento);
        }
        return lstOrcamentos;
    }
    //</editor-fold>
}